package com.evil.application.util;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.evil.application.constant.ApplicationConstant;
import com.evil.application.convert.DataConvert;
import com.evil.application.enums.form.control.ControlCodeEnum;
import com.evil.application.enums.order.OrderSpecialControlEnum;
import com.evil.application.pojo.bo.application.form.control.FormControlBO;
import com.evil.application.pojo.bo.application.form.control.option.FormControlOptionBO;
import com.evil.application.pojo.bo.application.judge.ApplicationJudgeBO;
import com.evil.application.pojo.bo.application.process.node.ProcessNodeBO;
import com.evil.application.pojo.bo.application.robot.rule.ApplicationRobotRuleBO;
import com.evil.application.pojo.dto.AppTreeDTO;
import com.evil.application.pojo.dto.ItemDTO;
import com.evil.application.pojo.dto.form.control.ControlBaseInfoDTO;
import com.evil.application.pojo.dto.form.control.code.ControlDTO;
import com.evil.application.pojo.dto.form.control.code.DeptSelControlDTO;
import com.evil.application.pojo.dto.form.control.code.MemberSelControlDTO;
import com.evil.application.pojo.dto.form.control.code.SelectControlDTO;
import com.evil.application.pojo.dto.form.control.code.config.ControlRelatedConfigDTO;
import com.evil.application.pojo.dto.form.control.code.config.ControlSelectConfigDTO;
import com.evil.application.pojo.dto.form.control.option.FormOptionRespDTO;
import com.evil.application.pojo.dto.form.control.related.ControlRelatedDTO;
import com.evil.application.pojo.dto.template.print.PrintTemplateConfigRespDTO;
import com.evil.application.pojo.entity.*;
import com.evil.common.account.dto.department.DepartmentBaseRespDTO;
import com.evil.common.account.dto.user.UserBaseRespDTO;
import com.evil.common.activiti.enums.HandleTypeEnum;
import com.evil.common.activiti.enums.NodeTypeEnum;
import com.evil.common.application.dto.form.SpecialControlConfigDTO;
import com.evil.common.application.dto.form.control.ControlBaseDTO;
import com.evil.common.application.dto.judge.JudgeOr;
import com.evil.common.application.dto.judge.JudgeSourceDTO;
import com.evil.common.application.dto.order.data.ControlDataDTO;
import com.evil.common.application.dto.order.node.OrderNodesDTO;
import com.evil.common.application.dto.permission.app.AppPermissionDTO;
import com.evil.common.application.dto.permission.app.AppPermissionSourceDTO;
import com.evil.common.application.dto.process.node.NodeRespInfoDTO;
import com.evil.common.application.dto.robot.RobotRuleDTO;
import com.evil.common.application.enums.ApplicationSourceTypeEnum;
import com.evil.common.application.enums.form.DefaultValueTypeEnum;
import com.evil.common.application.enums.judge.JudgeSourceTypeEnum;
import com.evil.common.application.enums.order.OrderProcessStatusEnum;
import com.evil.common.core.enums.BaseEnum;
import com.evil.common.family.enums.RCodeEnum;
import com.evil.common.core.enums.SwitchEnum;
import com.evil.common.core.exception.BusinessException;
import com.evil.common.core.util.ClassifyUtil;
import com.evil.common.core.util.GenerateUtil;
import com.evil.common.core.util.StreamUtil;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * 应用工具类
 *
 * @author liyang
 * @date 2022-08-08 00:00
 */
@Slf4j
public class ApplicationUtil implements ApplicationConstant {

    /**
     * 有意义控件id
     *
     * @param controlId controlId
     * @return boolean
     */
    public static boolean meaningful(Long controlId) {
        return Objects.nonNull(controlId) && !ApplicationUtil.DEFAULT_CONTROL_ID.equals(controlId);
    }

    /**
     * 层级分类应用包内组和应用列表
     *
     * @param items items
     * @return List
     */
    public static List<AppTreeDTO> classifyItem(List<AppTreeDTO> items) {
        Map<Long, AppTreeDTO> groupMap = StreamUtil.toMapFK(items, ItemDTO::getIsGroup, ItemDTO::getApplicationGroupId);

        Map<Long, List<AppTreeDTO>> groupAppsMap = items.stream()
                .filter(e -> !e.getIsGroup() && !DEFAULT_PARENT_APPLICATION_GROUP_ID.equals(e.getApplicationGroupId()))
                .collect(Collectors.groupingBy(ItemDTO::getApplicationGroupId));

        List<AppTreeDTO> tree = new ArrayList<>();
        items.forEach(e -> {
            if (e.getIsGroup()) {
                // 组
                e.setChildren(groupAppsMap.get(e.getApplicationGroupId()));
                tree.add(e);
            } else if (Long.valueOf("0").equals(e.getApplicationGroupId())) {
                // 根目录的应用
                tree.add(e);
            } else {
                // 组内应用
                if (!groupMap.containsKey(e.getApplicationGroupId())) {
                    // 如果该应用 当前没有所属组
                    tree.add(e);
                }
            }
        });

        return tree;
    }

    /**
     * 生成key
     *
     * @return String
     */
    public static String generateKey(Function<String, Boolean> checkDuplicateFun) {
        // 生成应用key
        return GenerateUtil.generateKey(new GenerateUtil.DefaultRandomType(), checkDuplicateFun);
    }

    /**
     * 层级分类 控件下拉选项
     *
     * @param options options
     * @return List
     */
    public static List<FormOptionRespDTO> classifyOptions(List<FormOptionRespDTO> options) {
        return ClassifyUtil.classify(
                options,
                FormOptionRespDTO::getOptionId,
                FormOptionRespDTO::getParentOptionId,
                Comparator.comparingLong(FormOptionRespDTO::getParentOptionId),
                FormOptionRespDTO::setChildrenOptions,
                DEFAULT_PARENT_OPTION_ID
        );
    }

    /**
     * 层级分类 控件下拉选项
     *
     * @param options options
     * @return List
     */
    public static List<FormControlOptionBO> classifyOptionBOs(List<FormControlOptionBO> options) {
        options.sort(Comparator.comparing(FormControlOptionBO::getSort));
        return ClassifyUtil.classify(
                options,
                FormControlOptionBO::getOptionId,
                FormControlOptionBO::getParentOptionId,
                Comparator.comparingLong(FormControlOptionBO::getParentOptionId),
                FormControlOptionBO::setChild,
                DEFAULT_PARENT_OPTION_ID
        );
    }

    /**
     * 层级分类控件列表
     *
     * @param controls controls
     * @return List
     */
    public static List<ControlDTO> classifyControl(List<ControlDTO> controls) {
        return ClassifyUtil.classify(
                controls,
                ControlDTO::getControlId,
                ControlDTO::getParentControlId,
                Comparator.comparingLong(ControlDTO::getParentControlId),
                ControlDTO::setChildControls,
                DEFAULT_PARENT_CONTROL_ID
        );
    }

    /**
     * 层级分类控件列表
     *
     * @param controls controls
     * @return List
     */
    public static List<ControlBaseInfoDTO> classifyBaseControl(List<ControlBaseInfoDTO> controls) {
        return ClassifyUtil.classify(
                controls,
                ControlBaseInfoDTO::getControlId,
                ControlBaseInfoDTO::getParentControlId,
                Comparator.comparingLong(ControlBaseInfoDTO::getParentControlId),
                ControlBaseInfoDTO::setChildControls,
                DEFAULT_PARENT_CONTROL_ID
        );
    }

    /**
     * 控件基础信息处理
     *
     * @param controlBases controlBases
     * @return List
     */
    public static List<ControlBaseInfoDTO> handlerControlBaseInfo(List<ControlBaseInfoDTO> controlBases) {
        Map<Long, ControlBaseInfoDTO> controlMap = StreamUtil.toMapK(controlBases, ControlBaseInfoDTO::getControlId);

        controlBases.forEach(e -> {
            if (!ApplicationUtil.DEFAULT_PARENT_CONTROL_ID.equals(e.getParentControlId())) {
                if (!controlMap.containsKey(e.getParentControlId())) {
                    throw new BusinessException(RCodeEnum.APPLICATION_FORM_CONTROL_NOT_EXIST);
                }
                ControlBaseInfoDTO parent = controlMap.get(e.getParentControlId());
                if (ControlCodeEnum.TABLE.getCode().equals(parent.getControlCode())) {
                    // 上级是表格
                    e.setControlTitle(String.format("%s-%s", ControlCodeEnum.TABLE.getName(), e.getControlTitle()));
                }
            }
        });
        return controlBases;
    }

    /**
     * 层级分类表单控件
     *
     * @param controls controls
     * @return List
     */
    public static List<FormControlBO> classifyControlBO(List<ApplicationFormControl> controls) {
        List<FormControlBO> controlBOList = controls.stream().map(FormControlBO::new).collect(Collectors.toList());
        return ClassifyUtil.classify(
                controlBOList,
                FormControlBO::getControlId,
                FormControlBO::getParentControlId,
                Comparator.comparingLong(FormControlBO::getParentControlId),
                FormControlBO::setChild,
                DEFAULT_PARENT_CONTROL_ID
        );
    }

    /**
     * 层级分类流程节点列表
     *
     * @param nodes nodes
     * @return NodeDTO
     */
    public static NodeRespInfoDTO classifyNode(List<NodeRespInfoDTO> nodes) {
        return ApplicationUtil.classifyNode(nodes, ApplicationUtil.DEFAULT_PARENT_NODE_ID);
    }

    /**
     * 层级分类流程节点列表，并且返回指定层级
     *
     * @param nodes        nodes
     * @param parentNodeId 父级节点ID
     * @return NodeDTO
     */
    public static NodeRespInfoDTO classifyNode(List<NodeRespInfoDTO> nodes, Long parentNodeId) {
        // 层级分类获取指定层级
        final List<NodeRespInfoDTO> classify = ClassifyUtil.classify(
                nodes,
                NodeRespInfoDTO::getNodeId,
                NodeRespInfoDTO::getParentNodeId,
                Comparator.comparingLong(NodeRespInfoDTO::getParentNodeId),
                (node, children) -> {
                    // 网关节点
                    node.setBranches(StreamUtil.filter(children, e -> NodeTypeEnum.INCLUSIVE_GATEWAY_NODE.getId() == e.getNodeType()));
                    // 普通节点
                    StreamUtil.isExistFirst(children, e -> NodeTypeEnum.INCLUSIVE_GATEWAY_NODE.getId() != e.getNodeType())
                            .ifPresent(node::setNextNode);
                },
                parentNodeId
        );

        if (classify.size() != 1) {
            throw new BusinessException(BaseEnum.RUN_ERROR, "流程节点数据异常");
        }
        return classify.get(0);
    }

    /**
     * 层级分类流程节点列表
     *
     * @param processNodes processNodes
     * @return List
     */
    public static List<ProcessNodeBO> classifyProcessNode(List<ApplicationProcessNode> processNodes) {
        List<ProcessNodeBO> nodeList = StreamUtil.transListT(processNodes, ProcessNodeBO::new);
        return ClassifyUtil.classify(
                nodeList,
                ProcessNodeBO::getNodeId,
                ProcessNodeBO::getParentNodeId,
                Comparator.comparingLong(ProcessNodeBO::getParentNodeId),
                ProcessNodeBO::setChildren,
                DEFAULT_PARENT_NODE_ID
        );
    }

    /**
     * 订单节点key
     *
     * @param orderId orderId
     * @param nodeId  nodeId
     * @return String
     */
    public static String orderNodeKey(Long orderId, Long nodeId) {
        return String.format("%s_%s", orderId, nodeId);
    }

    /**
     * 订单节点key
     *
     * @param orderNodes orderNodes
     * @return List
     */
    public static List<String> orderNodeKeys(OrderNodesDTO orderNodes) {
        return StreamUtil.transListT(orderNodes.getNodeIds(), nodeId -> ApplicationUtil.orderNodeKey(orderNodes.getOrderId(), nodeId));
    }

    /**
     * 还原订单节点keys
     *
     * @param orderNodeKeys orderNodeKeys
     * @return String
     */
    public static OrderNodesDTO restoreOrderNodeKeys(List<String> orderNodeKeys) {
        Map<Long, List<Long>> orderNodeIdsMap = orderNodeKeys.stream()
                .map(orderNodeKey -> orderNodeKey.split("_"))
                .collect(Collectors.groupingBy(s -> Long.valueOf(s[0]), Collectors.mapping(s -> Long.valueOf(s[1]), Collectors.toList())));

        return orderNodeIdsMap.entrySet().stream()
                .findFirst().map(entry -> new OrderNodesDTO(entry.getKey(), entry.getValue()))
                .orElseThrow(() -> new BusinessException(BaseEnum.RUN_ERROR));
    }

    /**
     * 订单节点所有组已处理
     *
     * @param groupNodeHandlers groupNodeHandlers
     * @return boolean
     */
    public static boolean orderNodeAllComplete(Map<String, List<ApplicationOrderNodeHandler>> groupNodeHandlers) {
        return groupNodeHandlers.entrySet().stream()
                .allMatch(entry -> entry.getValue().stream().anyMatch(e -> HandleTypeEnum.isHandled(e.getHandleType())));
    }

    /**
     * 层级分类 应用判断条件
     *
     * @param judgeList judgeList
     * @return List
     */
    public static List<ApplicationJudgeBO> classifyJudge(List<ApplicationJudge> judgeList) {
        List<ApplicationJudgeBO> judges = StreamUtil.transListT(judgeList, ApplicationJudgeBO::new);
        return ClassifyUtil.classify(
                judges,
                ApplicationJudgeBO::getJudgeId,
                ApplicationJudgeBO::getParentJudgeId,
                Comparator.comparingLong(ApplicationJudgeBO::getParentJudgeId),
                ApplicationJudgeBO::setChildren,
                DEFAULT_PARENT_JUDGE_ID
        );
    }

    /**
     * 控件转控件数据DTO
     *
     * @param applicationFormControl applicationFormControl
     * @return ControlDataDTO
     */
    public static ControlDataDTO controlToControlData(ApplicationFormControl applicationFormControl) {
        return BeanUtil.copyProperties(applicationFormControl, ControlDataDTO.class);
    }

    /**
     * 控件转控件数据DTO
     *
     * @param controlDTO controlDTO
     * @return ControlDataDTO
     */
    public static ControlDataDTO controlToControlData(ControlDTO controlDTO) {
        return BeanUtil.copyProperties(controlDTO, ControlDataDTO.class);
    }

    /**
     * 控件转控件数据DTO
     *
     * @param controlBaseInfoDTO controlBaseInfoDTO
     * @return ControlDataDTO
     */
    public static ControlDataDTO controlToControlData(ControlBaseInfoDTO controlBaseInfoDTO) {
        return BeanUtil.copyProperties(controlBaseInfoDTO, ControlDataDTO.class);
    }

    /**
     * 控件转控件数据DTO
     *
     * @param controls controls
     * @return List
     */
    public static List<ControlDataDTO> controlsToControlData(List<ApplicationFormControl> controls) {
        return controls.stream().map(ApplicationUtil::controlToControlData).collect(Collectors.toList());
    }

    /**
     * 控件转控件数据DTO
     *
     * @param controls controls
     * @return List
     */
    public static List<ControlDataDTO> controlDTOsToControlData(List<ControlDTO> controls) {
        return controls.stream().map(ApplicationUtil::controlToControlData).collect(Collectors.toList());
    }

    /**
     * 特殊控件
     *
     * @param specialControlConfigDTO specialControlConfigDTO
     * @param controls                controls
     * @param supplySpecialControl    supplySpecialControl
     * @return ApplicationFormControl 列表
     */
    public static List<ApplicationFormControl> supplySpecialControls(SpecialControlConfigDTO specialControlConfigDTO, List<ApplicationFormControl> controls, boolean supplySpecialControl) {
        if (supplySpecialControl) {
            OrderSpecialControlEnum.forEach(em -> controls.add(ApplicationUtil.createSpecialControl(em, specialControlConfigDTO)));
        }
        return controls;
    }

    /**
     * 创建特殊控件实体
     *
     * @param specialControlEnum specialControlEnum
     * @param specialConfigDto   specialConfigDto
     * @return ApplicationFormControl
     */
    public static ApplicationFormControl createSpecialControl(OrderSpecialControlEnum specialControlEnum, SpecialControlConfigDTO specialConfigDto) {
        // 补充特殊控件
        ApplicationFormControl control = new ApplicationFormControl();
        control.setControlId(specialControlEnum.getId());
        control.setControlCode(specialControlEnum.getControlCode().getCode());
        control.setControlField(specialControlEnum.getField());
        control.setControlTitle(specialControlEnum.getSpecialTitle().apply(specialConfigDto));
        control.setParentControlId(0L);
        return control;
    }

    /**
     * 创建特殊控件实体DTO
     *
     * @param specialControlEnum specialControlEnum
     * @param specialConfigDto   specialConfigDto
     * @return ApplicationFormControl
     */
    public static ControlDTO createSpecialControlDTO(OrderSpecialControlEnum specialControlEnum, SpecialControlConfigDTO specialConfigDto) {
        ApplicationFormControl specialControl = ApplicationUtil.createSpecialControl(specialControlEnum, specialConfigDto);
        ControlCodeEnum controlCodeEnum = ControlCodeEnum.findByCode(specialControl.getControlCode());
        return ApplicationUtil.controlsToDTO(controlCodeEnum, specialControl);
    }

    /**
     * 构建 控件实体数据 （判断特殊控件）
     *
     * @param form      form
     * @param controlId controlId
     * @param query     query
     * @return ControlDataDTO
     */
    public static ControlDataDTO handleControlToControlDataDTO(ApplicationForm form, Long controlId, Function<Long, ApplicationFormControl> query) {
        return OrderSpecialControlEnum.isExistById(controlId)
                .map(em -> {
                    SpecialControlConfigDTO specialControlConfigDTO = null == form ? null : ApplicationUtil.specialControlConfig(form.getSpecialControlConfig());
                    return ApplicationUtil.createSpecialControlDataDTO(em, specialControlConfigDTO);
                })
                .orElseGet(() -> ApplicationUtil.controlToControlData(query.apply(controlId)));
    }

    /**
     * 创建特殊控件实体DTO
     *
     * @param specialControlEnum specialControlEnum
     * @param specialConfigDto   specialConfigDto
     * @return ApplicationFormControl
     */
    public static ControlDataDTO createSpecialControlDataDTO(OrderSpecialControlEnum specialControlEnum, SpecialControlConfigDTO specialConfigDto) {
        ApplicationFormControl specialControl = ApplicationUtil.createSpecialControl(specialControlEnum, specialConfigDto);
        return ApplicationUtil.controlToControlData(specialControl);
    }

    /**
     * 构建 控件实体数据 （判断特殊控件）
     *
     * @param applicationForm applicationForm
     * @param controlId       controlId
     * @param query           query
     * @return ControlDataDTO
     */
    public static ControlDTO handleControlToControlDTO(ApplicationForm applicationForm, Long controlId, Function<Long, ApplicationFormControl> query) {
        return OrderSpecialControlEnum.isExistById(controlId)
                .map(em -> {
                    SpecialControlConfigDTO specialControlConfigDTO = ApplicationUtil.specialControlConfig(applicationForm.getSpecialControlConfig());
                    return ApplicationUtil.createSpecialControlDTO(em, specialControlConfigDTO);
                }).orElseGet(() -> ApplicationUtil.controlsToDTO(query.apply(controlId)));
    }

    /**
     * 构建 控件实体数据 （判断特殊控件）
     *
     * @param applicationForm applicationForm
     * @param controlId       controlId
     * @param dataConvert     dataConvert
     * @return ControlDataDTO
     */
    public static ControlDTO handleControlToControlDTO(ApplicationForm applicationForm, Long controlId, DataConvert dataConvert) {
        return OrderSpecialControlEnum.isExistById(controlId)
                .map(em -> {
                    SpecialControlConfigDTO specialControlConfigDTO = ApplicationUtil.specialControlConfig(applicationForm.getSpecialControlConfig());
                    return ApplicationUtil.createSpecialControlDTO(em, specialControlConfigDTO);
                }).orElseGet(() -> ApplicationUtil.controlsToDTO(dataConvert.getControl(controlId, false)));
    }

    /**
     * 构建 控件实体数据 （判断特殊控件）
     *
     * @param form      form
     * @param controlId controlId
     * @param query     query
     * @return ControlDataDTO
     */
    public static ControlDataDTO handleControlDTOToControlDataDTO(ApplicationForm form, Long controlId, Function<Long, ControlDTO> query) {
        return OrderSpecialControlEnum.isExistById(controlId)
                .map(em -> {
                    SpecialControlConfigDTO specialControlConfigDTO = null == form ? null : ApplicationUtil.specialControlConfig(form.getSpecialControlConfig());
                    return ApplicationUtil.createSpecialControlDataDTO(em, specialControlConfigDTO);
                }).orElseGet(() -> ApplicationUtil.controlToControlData(query.apply(controlId)));
    }

    /**
     * 转换表单 特殊控件配置
     *
     * @param specialControlConfig specialControlConfig
     * @return SpecialControlConfigDTO
     */
    public static SpecialControlConfigDTO specialControlConfig(String specialControlConfig) {
        return JSON.parseObject(specialControlConfig, SpecialControlConfigDTO.class);
    }

    /**
     * 检查是否开启控件关联
     *
     * @param controlDTO controlDTO
     * @return boolean
     */
    public static boolean checkControlRelated(ControlDTO controlDTO) {
        return ControlCodeEnum.checkControlRelated(controlDTO.getControlCode()) ||
                DefaultValueTypeEnum.RELATED_FORM.getId() == controlDTO.getDefaultValueType();
    }

    /**
     * 检查是否开启 通过公式运算
     *
     * @param controlDTO controlDTO
     * @return boolean
     */
    public static boolean checkControlFormula(ControlDTO controlDTO) {
        return DefaultValueTypeEnum.FORMULA_CALCULATION.getId() == controlDTO.getDefaultValueType();
    }

    /**
     * 表单控件转DTO
     *
     * @param controls    controls
     * @param dataConvert dataConvert
     * @return ControlDTO 列表
     */
    public static List<ControlDTO> controlsToDTO(Collection<ApplicationFormControl> controls, DataConvert dataConvert) {
        return StreamUtil.transListT(controls, c -> ApplicationUtil.controlsToDTO(c, dataConvert));
    }

    /**
     * 表单控件转DTO
     *
     * @param control control
     * @return ControlDTO 列表
     */
    public static ControlDTO controlsToDTO(ApplicationFormControl control) {
        ControlCodeEnum controlCodeEnum = ControlCodeEnum.findByCode(control.getControlCode());
        return ApplicationUtil.controlsToDTO(controlCodeEnum, control);
    }

    /**
     * 表单控件转DTO
     *
     * @param controlCodeEnum controlCodeEnum
     * @param control         control
     * @return ControlDTO 列表
     */
    public static ControlDTO controlsToDTO(ControlCodeEnum controlCodeEnum, ApplicationFormControl control) {
        try {
            Constructor<? extends ControlDTO> constructor = controlCodeEnum.getControlClass().getConstructor(ApplicationFormControl.class);
            return constructor.newInstance(control);
        } catch (NoSuchMethodException | InstantiationException | IllegalAccessException |
                 InvocationTargetException e) {
            log.error("caseControlDTO error: ", e);
            throw new BusinessException(BaseEnum.RUN_ERROR);
        }
    }

    /**
     * 表单控件转DTO
     *
     * @param control     control
     * @param dataConvert dataConvert
     * @return ControlDTO 列表
     */
    public static ControlDTO controlsToDTO(ApplicationFormControl control, DataConvert dataConvert) {
        ControlCodeEnum controlCodeEnum = ControlCodeEnum.findByCode(control.getControlCode());
        ControlDTO controlDTO = ApplicationUtil.controlsToDTO(controlCodeEnum, control);
        if (Objects.isNull(dataConvert)) {
            return controlDTO;
        }
        ControlRelatedConfigDTO controlRelatedConfigDTO = new ControlRelatedConfigDTO();
        controlDTO.setControlRelatedConfig(controlRelatedConfigDTO);

        // 普通选择
        if (controlDTO instanceof SelectControlDTO selectControlRespDTO) {
            List<FormOptionRespDTO> options = dataConvert.getOptionByControlId(control.getControlId(), true);
            // 其他选项
            if (SwitchEnum.isOpen(selectControlRespDTO.getOtherSelect())) {
                options.add(ApplicationUtil.otherSelect());
            }
            selectControlRespDTO.setOptionsData(options);
            selectControlRespDTO.setOptions(ApplicationUtil.classifyOptions(options));
        }
        // 成员选择
        if (controlDTO instanceof MemberSelControlDTO memberSelControl) {
            if (null == memberSelControl.getControlSelectConfig()) {
                memberSelControl.setControlSelectConfig(new ControlSelectConfigDTO());
            }
            ControlSelectConfigDTO controlSelectConfigDTO = memberSelControl.getControlSelectConfig();

            List<AppPermissionDTO> dynamic = controlSelectConfigDTO.getDynamic();
            // 成员选择
            int appSourceType = ApplicationSourceTypeEnum.FORM_CONTROL_MEMBER_SELECT_SCOPE.getId();
            if (dynamic.size() > 0) {
                // 补充权限源类型
                dynamic.forEach(e -> e.setSourceType(ApplicationSourceTypeEnum.MEMBER_CONTROL_DEFAULT_VALUE.getId()));
                // 补充权限目标对象
                TreeSet<UserBaseRespDTO> userBaseRespDTOS = dataConvert.getUserBaseList(dynamic)
                        .stream()
                        .collect(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(UserBaseRespDTO::getUserId))));
                memberSelControl.setDefaultValue(JSON.toJSONString(userBaseRespDTOS));
            }
            controlSelectConfigDTO.setScope(dataConvert.findBySource(new AppPermissionSourceDTO(appSourceType, control.getControlId())));
        }
        // 部门选择
        if (controlDTO instanceof DeptSelControlDTO deptSelControlDTO) {
            if (null == deptSelControlDTO.getControlSelectConfig()) {
                deptSelControlDTO.setControlSelectConfig(new ControlSelectConfigDTO());
            }
            ControlSelectConfigDTO controlSelectConfigDTO = deptSelControlDTO.getControlSelectConfig();

            List<AppPermissionDTO> dynamic = controlSelectConfigDTO.getDynamic();
            // 部门选择
            int appSourceType = ApplicationSourceTypeEnum.FORM_CONTROL_DEPT_SELECT_SCOPE.getId();
            if (dynamic.size() > 0) {
                // 补充权限源类型
                dynamic.forEach(e -> e.setSourceType(ApplicationSourceTypeEnum.DEPARTMENT_CONTROL_DEFAULT_VALUE.getId()));
                // 补充权限目标对象
                TreeSet<DepartmentBaseRespDTO> departmentBaseRespDTOS = dataConvert.getDepartmentBaseList(dynamic)
                        .stream()
                        .collect(Collectors.toCollection(
                                () -> new TreeSet<>(Comparator.comparing(DepartmentBaseRespDTO::getDepartmentId))));
                deptSelControlDTO.setDefaultValue(JSON.toJSONString(departmentBaseRespDTOS));
            }
            controlSelectConfigDTO.setScope(dataConvert.findBySource(new AppPermissionSourceDTO(appSourceType, control.getControlId())));
        }

        // 筛选条件
        if (ApplicationUtil.checkControlRelated(controlDTO)) {
            // 关联控件
            List<ControlRelatedDTO> controlRelatedBases = StreamUtil.filter(dataConvert.getControlRelatedBases(control.getControlId()), e -> {
                // 检查关联表单是否存在
                ApplicationForm form = dataConvert.getForm(e.getRelatedFormId(), false);
                if (null == form) {
                    return false;
                }
                // 关联特殊控件
                if (!OrderSpecialControlEnum.isSpecialControlId(e.getRelatedControlId())) {
                    ApplicationFormControl relatedControl = dataConvert.getControl(e.getRelatedControlId(), false);
                    return null != relatedControl;
                }
                return true;
            });
            // 有效
            if (!controlRelatedBases.isEmpty()) {
                int judgeSourceType = JudgeSourceTypeEnum.CONTROL_RELATED_FILTER_CONDITION.getId();
                List<JudgeOr> judgeOrs = dataConvert.getJudgeBySource(new JudgeSourceDTO(judgeSourceType, control.getControlId()));

                controlRelatedConfigDTO.setControlRelatedBases(controlRelatedBases);
                controlRelatedConfigDTO.setJudgeOrs(judgeOrs);
            }
        }

        return controlDTO;
    }

    /**
     * 表单控件转Base
     *
     * @param controls    controls
     * @param dataConvert dataConvert
     * @return ControlBaseInfoDTO 列表
     */
    public static List<ControlBaseInfoDTO> controlToBase(Collection<ApplicationFormControl> controls, DataConvert dataConvert) {
        return controls.stream()
                .map(c -> {
                    final ControlBaseInfoDTO controlBase = BeanUtil.copyProperties(c, ControlBaseInfoDTO.class);
                    final ControlCodeEnum controlCodeEnum = ControlCodeEnum.findByCode(controlBase.getControlCode());

                    // 选项
                    if (controlCodeEnum.hasOptions()) {

                        List<FormOptionRespDTO> options = dataConvert.getOptionByControlId(c.getControlId(), true);
                        // 其他选项
                        if (SwitchEnum.isOpen(c.getOtherSelect())) {
                            options.add(ApplicationUtil.otherSelect());
                        }
                        controlBase.setOptions(ApplicationUtil.classifyOptions(options));
                    }
                    return controlBase;
                })
                .collect(Collectors.toList());
    }

    /**
     * 层级分类并且补充流程节点控件选项值
     *
     * @param controlBases 控件基础信息列表
     * @param nodes        流程节点列表
     * @return List
     */
    public static List<ControlBaseInfoDTO> handleControlBases(List<ControlBaseInfoDTO> controlBases, List<ApplicationProcessNode> nodes) {
        // 节点控件处理
        StreamUtil.isExistFirst(controlBases, c -> OrderSpecialControlEnum.NODE.getId().equals(c.getControlId())).ifPresent(c -> {
            // 流程节点列表
            List<FormOptionRespDTO> options = nodes.stream()
                    .filter(e -> NodeTypeEnum.START_EVENT.getId() != e.getNodeType())
                    .map(e -> {
                        FormOptionRespDTO formOptionRespDTO = new FormOptionRespDTO();
                        formOptionRespDTO.setOptionId(e.getNodeId());
                        if (NodeTypeEnum.END_EVENT.getId() == e.getNodeType()) {
                            formOptionRespDTO.setOptionName(OrderProcessStatusEnum.COMPLETED.getName());
                            formOptionRespDTO.setOptionValue(OrderProcessStatusEnum.COMPLETED.getName());
                        } else {
                            formOptionRespDTO.setOptionName(e.getNodeName());
                            formOptionRespDTO.setOptionValue(e.getNodeName());
                        }
                        return formOptionRespDTO;
                    }).collect(Collectors.toList());

            // 流程拒绝特殊节点
            options.add(ApplicationUtil.buildNodeOptions(OrderProcessStatusEnum.REFUSE));
            // 流程已完成特殊节点
            options.add(ApplicationUtil.buildNodeOptions(OrderProcessStatusEnum.COMPLETED));
            // 草稿箱特殊节点
            options.add(ApplicationUtil.buildNodeOptions(OrderProcessStatusEnum.DRAFT_BOX));
            c.setOptions(options);
        });

        // 层级分类
        controlBases = ApplicationUtil.classifyBaseControl(controlBases);
        // 排序
        controlBases.sort(Comparator.comparing(c -> {
            if (OrderSpecialControlEnum.isSpecialControlId(c.getControlId())) {
                OrderSpecialControlEnum specialControlEnum = OrderSpecialControlEnum.findById(c.getControlId());
                return specialControlEnum.isFront() ? -1 : 1;
            }
            return 0;
        }));
        return controlBases;
    }

    /**
     * 生产流程节点选项
     *
     * @param orderProcessStatusEnum orderProcessStatusEnum
     * @return FormOptionRespDTO
     */
    public static FormOptionRespDTO buildNodeOptions(OrderProcessStatusEnum orderProcessStatusEnum) {
        FormOptionRespDTO formOptionRespDTO = new FormOptionRespDTO();
        formOptionRespDTO.setOptionId(-(long) OrderProcessStatusEnum.REFUSE.getId());
        formOptionRespDTO.setOptionName(OrderProcessStatusEnum.REFUSE.getName());
        formOptionRespDTO.setOptionValue(OrderProcessStatusEnum.REFUSE.getName());
        return formOptionRespDTO;
    }

    /**
     * 生成其他选项
     *
     * @return FormOptionRespDTO
     */
    public static FormOptionRespDTO otherSelect() {
        FormOptionRespDTO otherOpt = new FormOptionRespDTO();
        otherOpt.setOptionId(0L);
        otherOpt.setParentOptionId(0L);
        otherOpt.setOptionName("其他");
        otherOpt.setOptionValue("其他");
        otherOpt.setBeingOtherOpt(true);
        return otherOpt;
    }

    /**
     * 层级分类机器人规则列表
     *
     * @param robotRules robotRules
     * @return List
     */
    public static List<RobotRuleDTO> classifyRobotRuleDTO(List<RobotRuleDTO> robotRules) {
        return ClassifyUtil.classify(
                robotRules,
                RobotRuleDTO::getRobotRuleId,
                RobotRuleDTO::getParentRobotRuleId,
                Comparator.comparingLong(RobotRuleDTO::getParentRobotRuleId),
                RobotRuleDTO::setChildren,
                DEFAULT_PARENT_ROBOT_RULE_ID
        );
    }

    /**
     * 层级分类机器人规则列表
     *
     * @param robotRules robotRules
     * @return List
     */
    public static List<ApplicationRobotRuleBO> classifyRobotRule(List<ApplicationRobotRule> robotRules) {
        List<ApplicationRobotRuleBO> robotRuleBOList = robotRules.stream().map(ApplicationRobotRuleBO::new).collect(Collectors.toList());
        return ClassifyUtil.classify(
                robotRuleBOList,
                ApplicationRobotRuleBO::getRobotRuleId,
                ApplicationRobotRuleBO::getParentRobotRuleId,
                Comparator.comparingLong(ApplicationRobotRuleBO::getParentRobotRuleId),
                ApplicationRobotRuleBO::setChildren,
                DEFAULT_PARENT_ROBOT_RULE_ID
        );
    }

    /**
     * 获取控件选项Map
     *
     * @param controls controls
     * @return Map
     */
    public static Map<Long, Map<String, FormOptionRespDTO>> getOptionMapForControls(List<ControlDTO> controls) {
        return StreamUtil.toMapAndThen(
                StreamUtil.transListFT(controls, c -> c instanceof SelectControlDTO, c -> (SelectControlDTO) c),
                SelectControlDTO::getControlId,
                SelectControlDTO::getOptions,
                FormOptionRespDTO::getOptionName
        );
    }

    /**
     * 展开控件子级
     *
     * @param controlBases controlBases
     * @param controlIds   过滤控件
     * @param unfoldCodes  需要展开子级控件类型
     * @return List
     */
    public static List<ControlBaseInfoDTO> unfoldControlChildren(List<ControlBaseInfoDTO> controlBases, Collection<Long> controlIds, ControlCodeEnum... unfoldCodes) {
        List<String> codes = Arrays.stream(unfoldCodes).map(ControlCodeEnum::getCode).toList();
        // 展开指定类型控件的子级
        List<ControlBaseInfoDTO> controlBaseInfos = new ArrayList<>();
        for (ControlBaseInfoDTO controlBase : controlBases) {
            // 有子级
            if (!controlBase.getChildControls().isEmpty()) {
                // 需要展开子级
                if (codes.contains(controlBase.getControlCode())) {
                    List<ControlBaseInfoDTO> children = ApplicationUtil.unfoldControlChildren(controlBase.getChildControls(), controlIds, unfoldCodes);
                    // 有子级可见
                    if (!children.isEmpty()) {
                        // 非标签页，则父级固定可见
                        if (ControlCodeEnum.TABS.getCode().equals(controlBase.getControlCode())) {
                            controlBaseInfos.add(controlBase);
                        }
                        controlBaseInfos.addAll(children);
                    }
                }
                // 不需要展开子级
                else {
                    // 不过滤，或者过滤通过
                    if (CollectionUtil.isEmpty(controlIds) || controlIds.contains(controlBase.getControlId())) {
                        controlBaseInfos.add(controlBase);
                    }
                }
            }
            // 没有子级
            else {
                // 不过滤，或者过滤通过
                if (CollectionUtil.isEmpty(controlIds) || controlIds.contains(controlBase.getControlId())) {
                    controlBaseInfos.add(controlBase);
                }
            }
        }
        return controlBaseInfos;
    }

    /**
     * 获取指定用户（登陆人）处理节点，不存在抛出异常
     *
     * @param nodeHandlers nodeHandlers
     * @param handlerId    handlerId
     * @param handleType   handleType
     * @return ApplicationOrderNodeHandler
     */
    public static ApplicationOrderNodeHandler nodeHandler(List<ApplicationOrderNodeHandler> nodeHandlers, Long handlerId, int handleType, Supplier<Long> getLoginUserId) {
        // 如果是转交，则获取当前登录用户
        Long currentHandlerId = HandleTypeEnum.REASSIGNMENT.getId() == handleType ? getLoginUserId.get() : handlerId;
        // 如果是发起新的，则获取发起人 处理信息
        boolean isStart = HandleTypeEnum.START.getId() == handleType;
        int currentHandleType = isStart ? HandleTypeEnum.START.getId() : HandleTypeEnum.PROCESSING.getId();
        return nodeHandlers.stream()
                .filter(e -> currentHandlerId.equals(e.getHandlerId()) && currentHandleType == e.getHandleType())
                .min(Comparator.comparing(ApplicationOrderNodeHandler::getHandlerGroup))
                .orElseThrow(() -> new BusinessException(RCodeEnum.ERROR_UNAUTHORIZED));
    }

    /**
     * 构建控件模板
     *
     * @param controlBases controlBases
     * @return TemplateConfigRespDTO 列表
     */
    public static List<PrintTemplateConfigRespDTO> buildControlTemplateConfig(Collection<ControlBaseDTO> controlBases, List<Long> controlIds) {
        boolean empty = CollectionUtil.isEmpty(controlIds);
        return StreamUtil.transListFT(controlBases, e -> empty || controlIds.contains(e.getControlId()), ApplicationUtil::buildControlTemplateConfig);
    }

    /**
     * 构建控件模板
     *
     * @param controlBase controlBase
     * @return TemplateConfigRespDTO
     */
    public static PrintTemplateConfigRespDTO buildControlTemplateConfig(ControlBaseDTO controlBase) {
        PrintTemplateConfigRespDTO printTemplateConfigRespDTO = new PrintTemplateConfigRespDTO();
        printTemplateConfigRespDTO.setControlCodeName(ControlCodeEnum.findByCode(controlBase.getControlCode()).getName());
        printTemplateConfigRespDTO.setControlId(controlBase.getControlId());
        printTemplateConfigRespDTO.setParentControlId(controlBase.getParentControlId());
        printTemplateConfigRespDTO.setControlTitle(controlBase.getControlTitle());
        printTemplateConfigRespDTO.setFieldCode(ApplicationUtil.generateControlTemplateConfig(controlBase.getControlTitle(), controlBase.getControlField()));
        return printTemplateConfigRespDTO;
    }

    /**
     * 构建控件模板
     *
     * @param controlTitle controlTitle
     * @param controlField controlField
     * @return String
     */
    public static String generateControlTemplateConfig(String controlTitle, String controlField) {
        return String.format("{{%s$$%s}}", controlTitle, controlField);
    }

    /**
     * 有意义的id
     *
     * @param id id
     * @return boolean
     */
    public static boolean meaningfulId(Long id) {
        return 0L < id;
    }
}
